#include "Gaussian.h"

Gaussian::Gaussian(const WORD samples) : samples(samples)
{
	sampleOffsetsH.resize(samples);
	sampleWeightsH.resize(samples);
	sampleOffsetsV.resize(samples);
	sampleWeightsV.resize(samples);
}

Gaussian::~Gaussian(void)
{
	sampleOffsetsH.clear();
	sampleWeightsH.clear();
	sampleOffsetsV.clear();
	sampleWeightsV.clear();
}

FLOAT Gaussian::ComputeGaussian(const FLOAT n)
{
	FLOAT theta = 2.0f + D3DX_16F_EPSILON;
	return theta = (FLOAT)((1.0 / sqrt(2 * D3DX_PI * theta)) * exp(-(n * n) / (2 * theta * theta)));
}

void Gaussian::setBlurParametersH(const FLOAT dx, const FLOAT dy)
{
	setBlurParameters(dx, dy, sampleOffsetsH, sampleWeightsH);	
}

void Gaussian::setBlurParametersV(const FLOAT dx, const FLOAT dy)
{
	
	setBlurParameters(dx, dy, sampleOffsetsV, sampleWeightsV);
}

// Lifted from Mahdi's Post Processor (TM)
void Gaussian::setBlurParameters(const FLOAT dx, const FLOAT dy, std::vector<D3DXVECTOR4> &vSampleOffsets, std::vector<float> &fSampleWeights)
{
	// The first sample always has a zero offset.
	fSampleWeights[0] = ComputeGaussian(0);
	vSampleOffsets[0] = D3DXVECTOR4(0, 0, 0, 0);

	// Maintain a sum of all the weighting values.
	FLOAT totalWeights = fSampleWeights[0];

	// Add pairs of additional sample taps, positioned
	// along a line in both directions from the center.
	for (WORD i = 0; i < samples / 2; i++)
	{
		// Store weights for the positive and negative taps.
		FLOAT weight = ComputeGaussian(i + 1);

		fSampleWeights[i * 2 + 1] = weight;
		fSampleWeights[i * 2 + 2] = weight;

		totalWeights += weight * 2;

		// To get the maximum amount of blurring from a limited number of
		// pixel shader samples, we take advantage of the bilinear filtering
		// hardware inside the texture fetch unit. If we position our texture
		// coordinates exactly halfway between two texels, the filtering unit
		// will average them for us, giving two samples for the price of one.
		// This allows us to step in units of two texels per sample, rather
		// than just one at a time. The 1.5 offset kicks things off by
		// positioning us nicely in between two texels.
		FLOAT sampleOffset = i * 2 + 1.5f;

		D3DXVECTOR4 delta = D3DXVECTOR4(dx, dy, 0, 0) * sampleOffset;

		// Store texture coordinate offsets for the positive and negative taps.
		vSampleOffsets[i * 2 + 1] = delta;
		vSampleOffsets[i * 2 + 2] = -delta;
	}

	// Normalize the list of sample weightings, so they will always sum to one.
	for (int i = 0; i < fSampleWeights.size(); i++)
	{
		fSampleWeights[i] /= totalWeights;
	}
}